package org.water.base.support;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.SQLQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import org.water.base.entity.AbstractEntity;
import org.water.base.repository.BaseRepository;
import org.water.base.repository.hibernate.Transformers;



/**
 * 基础dao实现
 * @author qzy
 *
 * @param <M> 实体表类型
 * @param <ID> 主键类型
 */
@SuppressWarnings("deprecation")
@Transactional(readOnly=true)
public class SimpleBaseRepository<M extends AbstractEntity<Serializable>, ID extends Serializable> extends SimpleJpaRepository<M, ID>
  implements BaseRepository<M, ID> {

	private final EntityManager em;
	private static Logger logger=LogManager.getLogger(SimpleBaseRepository.class);
	/**
	 * 主键字段名
	 */
	private String idField="id";
	 private Class<M> entityClass;
	
	public SimpleBaseRepository(JpaEntityInformation<M, ID> entityInformation, EntityManager entityManager) {
		super(entityInformation, entityManager);
		this.em=entityManager;
		this.entityClass=getDomainClass();
		logger.debug(" create simpleBaseRepository");
	}
	/**
	 * 根据主键查询数据
	 * @param id
	 * @return
	 */
	public M findOne(ID id)
	{
	   return findById(id).get();	
	}
	/**
	 * 根据主键删除单个
	 */
    @Override
    @Transactional
    public void delete(final ID id) 
    {
    	super.deleteById(id);
    }
    /**
     * 根据主键删除多个
     * @param ids
     */
	@Override
	@Transactional
	public void delete(ID[] ids) {
		 if (ArrayUtils.isEmpty(ids)) {
	            return;
        }
		List<M> models = new ArrayList<M>();
		for (ID id : ids) {
	            M model = null;
	            try {
	                model = entityClass.newInstance();
	            } catch (Exception e) {
	                throw new RuntimeException("batch delete " + entityClass + " error", e);
	            }
	            try {
	                BeanUtils.setProperty(model, idField, id);
	            } catch (Exception e) {
	                throw new RuntimeException("batch delete " + entityClass + " error, can not set id", e);
	            }
	            models.add(model);
	       }
		deleteInBatch(models);
	}
	/**
	 * 列表查询询map   
	 * 原生态SQL查询，返回List<Map<String, Object>>
	 * @param sql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> createNativeQueryToMap(String sql){
		Query query = getEntityManager().createNativeQuery(sql);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_LOWER_TO_ENTITY_MAP);
		return query.getResultList();
	}
	/**
	 * 列表查询 map
	 * 原生态SQL查询，返回List<Map<String, Object>>
	 * @param sql
	 * @param params  键值对传参
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> createNativeQueryToMap(String sql,Map<String, Object> params){
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_LOWER_TO_ENTITY_MAP);
		return query.getResultList();
	}
	
	/**
	 * 列表查询map
	 * 原生态SQL查询，返回List<Map<String, Object>>
	 * @param sql
	 * @param params  顺序传参
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> createNativeQueryToMap(String sql,Object[] params){
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_LOWER_TO_ENTITY_MAP);
		return query.getResultList();
	}
	/**
	 * 列表查询bean  
	 * 原生态SQL查询，返回List<bean>
	 * @param sql
	 * @param resultClass //返回结果bean class
	 * @return
	 */
	/**@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<M> createNativeQueryToBean(String sql,Class resultClass){
		Query query = getEntityManager().createNativeQuery(sql,resultClass);
		//query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));
		return query.getResultList();
	}**/
	/**
	 * 列表查询 bean
	 * 原生态SQL查询，返回List<bean>
	 * @param sql
	 * @param params  键值对传参
	 * @param resultClass //返回结果bean class
	 * @return
	 */
	/**@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<M> createNativeQueryToBean(String sql,Map<String, Object> params,Class resultClass){
		Query query = getEntityManager().createNamedQuery(sql,resultClass);
		SqlHelper.buildQueryParams(query, params);
		//query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));
		return query.getResultList();
	}**/
	
	/**
	 * 列表查询bean
	 * 原生态SQL查询，返回List<bean>
	 * @param sql
	 * @param params  顺序传参
	 * @param resultClass //返回结果bean class
	 * @return
	 */
	/**@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<M> createNativeQueryToBean(String sql,Object[] params,Class resultClass){
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));
		return query.getResultList();
	}**/
	/**
	 * 分页查询map
	 * 原生态SQL查询，返回Page<Map<String, Object>>
	 * @param sql
	 * @param params   键值对传参
	 * @param pageable
	 * @return
	 */
	public Page<Map<String,Object>> createNativeQueryToMap(String sql,Map<String, Object> params,final Pageable pageable){
		Query count = getEntityManager().createNativeQuery("select count(*) from ("+sql+")x");
		SqlHelper.buildQueryParams(count, params);
		Long total = Long.parseLong(count.getSingleResult().toString());
		
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		query.setFirstResult((int) pageable.getOffset());
		query.setMaxResults(pageable.getPageSize());
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_LOWER_TO_ENTITY_MAP);
		@SuppressWarnings("unchecked")
		List<Map<String,Object>> content = query.getResultList();
		return new PageImpl<Map<String,Object>>(
				content,
                pageable,
                total
        );
	}
	/**
	 * 分页查询map
	 * 原生态SQL查询，返回Page<Map<String, Object>>
	 * @param sql
	 * @param params 顺序传参
	 * @param pageable
	 * @return
	 */
	public Page<Map<String, Object>> createNativeQueryToMap(String sql,Object[] params,final Pageable pageable){
		Query count = getEntityManager().createNativeQuery("select count(*) from ("+sql+")x");
		SqlHelper.buildQueryParams(count, params);
		Long total = Long.parseLong(count.getSingleResult().toString());
		
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		query.setFirstResult((int) pageable.getOffset());
		query.setMaxResults(pageable.getPageSize());
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_LOWER_TO_ENTITY_MAP);
		@SuppressWarnings("unchecked")
		List<Map<String, Object>> content = query.getResultList();
		return new PageImpl<Map<String, Object>>(
				content,
                pageable,
                total
        );
	}
	/**
	 * 分页查询bean
	 * 原生态SQL查询，返回List<bean>
	 * @param sql
	 * @param params  键值对传参
	 * @param pageable
	 * @param resultClass //返回结果bean class
	 * @return
	 */
	/**@SuppressWarnings({ "rawtypes", "unchecked" })
	public Page<M> createNativeQueryToBean(String sql,Map<String, Object> params,final Pageable pageable,Class resultClass){
		Query count = getEntityManager().createNativeQuery("select count(*) from ("+sql+")x");
		SqlHelper.buildQueryParams(count, params);
		Long total = Long.parseLong(count.getSingleResult().toString());
		
		Query query = getEntityManager().createNamedQuery(sql,resultClass);
		SqlHelper.buildQueryParams(query, params);
		query.setFirstResult(pageable.getOffset());
		query.setMaxResults(pageable.getPageSize());
		//query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));
		List<M> content = query.getResultList();
		return new PageImpl<M>(
				content,
                pageable,
                total
        );
	}**/
	/**
	 * 分页查询 bean
	 * 原生态SQL查询，返回Page<Bean>
	 * @param sql
	 * @param params 顺序传参
	 * @param pageable
	 * @param resultClass //返回结果bean class
	 * @return
	 */
	/***@SuppressWarnings({ "rawtypes", "unchecked" })
	public Page<M> createNativeQueryToBean(String sql,Object[] params,final Pageable pageable,Class resultClass){
		Query count = getEntityManager().createNativeQuery("select count(*) from ("+sql+")x");
		SqlHelper.buildQueryParams(count, params);
		Long total = Long.parseLong(count.getSingleResult().toString());
		
		Query query = getEntityManager().createNativeQuery(sql,resultClass);
		SqlHelper.buildQueryParams(query, params);
		query.setFirstResult(pageable.getOffset());
		query.setMaxResults(pageable.getPageSize());
		//query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));
		List<M> content = query.getResultList();
		return new PageImpl<M>(
				content,
                pageable,
                total
        );
	}**/
	/**
	 * bean查询
	 * @param class1
	 * @return
	 */
	/**public BeanQuery<M> createBeanQuery(Class<M> clazz)
	{
		BeanQuery<M> beanQuery=new BeanQuery<M>(clazz,em);
		return beanQuery;
	} **/
	
	/**
	 * 执行原生sql语句,更新/插入  
	 * @param sql
	 * @param params
	 */
	@Transactional(readOnly=false)
	public Integer excuteNativeSql(String sql,Object[] params)
	{
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		return  query.executeUpdate();
	}
	/**
	 * 执行原生sql语句  ,更新/插入  
	 * @param sql
	 * @param params
	 */
	@Transactional(readOnly=false)
	public Integer excuteNativeSql(String sql,Map<String, Object> params)
	{
		Query query = getEntityManager().createNativeQuery(sql);
		SqlHelper.buildQueryParams(query, params);
		return  query.executeUpdate();
	}
	/**
	 * bean查询
	 */
	public <T> BeanQuery<T> createBeanQuery(Class<T> clazz)
	{
		BeanQuery<T> beanQuery=new BeanQuery<T>(clazz,em);
		return beanQuery;
	} 
	/**
	 * 刷新
	 */
	@Override
	public void refresh(M t) {
		this.em.refresh(t);
	}
    /**
     * 实体管理器
     */
	@Override
	public EntityManager getEntityManager() {
		return this.em;
	}
}
